package com.wolfsea.defineviewpageindicator
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Rect
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
import android.view.View
import androidx.appcompat.widget.LinearLayoutCompat
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.get
import kotlin.math.abs

/**
 *@desc ViewContainer
 *@author liuliheng
 *@time 2022/10/24  21:50
 **/
class ViewContainer @JvmOverloads constructor(
    context: Context,
    attributeSet: AttributeSet? = null
) : ConstraintLayout(context, attributeSet) {

    private var downX = 0
    private var downY = 0
    private var downFlagX = 0
    private var downFlagY = 0

    private var movedX = 0
    private var circleMovedX = 0
    private var circleBaseMovedX = 0

    private var pointerDownX = 0
    private var pointerDownFlagX = 0
    private var pointerDownY = 0
    private var pointerDownFlagY = 0

    private var currentIndex = 0
    private var currentMoveState = STATE_NONE

    private var currentPage = -1

    private var currentPointerId = 0

    private var pageChildCount = 0

    private var updatePage = true
    private var usedMultiPointTouch = false

    private val selectedPaint by lazy {
        Paint().apply {
            isAntiAlias = true
            isDither = true
            style = Paint.Style.FILL
            strokeWidth = context.resources.getDimension(R.dimen.dp_2)
            color = Color.CYAN
        }
    }

    private val unSelectedPaint by lazy {
        Paint().apply {
            isAntiAlias = true
            isDither = true
            style = Paint.Style.STROKE
            strokeWidth = context.resources.getDimension(R.dimen.dp_2)
            color = Color.CYAN
        }
    }

    /*存储x值Map*/
    private val x0ValueMap = HashMap<Int, Pair<Float, Float>>()
    private val x1ValueMap = HashMap<Int, Pair<Float, Float>>()

    private val circleBaseDistance = context.resources.getDimension(R.dimen.dp_50).toInt()
    private val circlesDistance = context.resources.getDimension(R.dimen.dp_5)

    init {
        setWillNotDraw(false)
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        measureChildren(widthMeasureSpec, heightMeasureSpec)
        pageChildCount = childCount
        circleBaseMovedX = (measuredWidth / 3.0f / pageChildCount).toInt()
        if (updatePage) {
            showNextPage(currentPage, false)
            updatePage = false
        }
    }

    override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
        super.onLayout(changed, l, t, r, b)
        for (index in 0.until(childCount)) {
            val view = getChildAt(index)
            if (view != null && view is ConstraintLayout) {
                view.layout(
                    l + movedX + measuredWidth * index,
                    t,
                    r + movedX + measuredWidth * (index + 1),
                    b
                )
               // Log.d(TAG, "view is ConstraintLayout,index:${index}")
            }
        }
    }

    override fun onTouchEvent(event: MotionEvent?): Boolean {
        performClick()
        Log.d(TAG,"onTouchEvent")
        when (event?.actionMasked) {
            MotionEvent.ACTION_DOWN -> {
                Log.d(TAG, "onTouchEvent---ACTION_DOWN")
                val pointerIndex = event.findPointerIndex(currentPointerId)
                downFlagX = event.getX(pointerIndex).toInt()
                downFlagY = event.getY(pointerIndex).toInt()
                downX = downFlagX
                downY = downFlagY
            }
            MotionEvent.ACTION_POINTER_DOWN -> {
                Log.d(TAG, "onTouchEvent---ACTION_POINTER_DOWN")
                usedMultiPointTouch = true
                val pointerCount = event.pointerCount
                currentPointerId++
                Log.d(TAG, "pointerCount:${pointerCount},currentPointerId:${currentPointerId}")
                val pointerIndex = event.findPointerIndex(currentPointerId)
                pointerDownFlagX = event.getX(pointerIndex).toInt()
                pointerDownX = pointerDownFlagX
                pointerDownFlagY = event.getY(pointerIndex).toInt()
                pointerDownY = pointerDownFlagY
            }
            MotionEvent.ACTION_MOVE -> {
                Log.d(TAG, "onTouchEvent---ACTION_MOVE")
                //横向滑动才移动
                if (event.pointerCount == 1) {
                    currentPointerId = 0
                    var pointerIndex = event.findPointerIndex(currentPointerId)
                    if (pointerIndex != 0) {
                        pointerIndex = 0
                    }
                    val actionMoveX = event.getX(pointerIndex).toInt()
                    val actionMoveY = event.getY(pointerIndex).toInt()
                    val diffValueX = actionMoveX - downX
                    val diffValueY = actionMoveY - downY
                    if (abs(diffValueX) > abs(diffValueY)) {
                        handleMoveEvent(diffValueX)
                        requestLayout()
                    }
                    Log.d(TAG, "actionMoveX:${actionMoveX},actionMoveY:${actionMoveY}")
                    downX = actionMoveX
                    downY = actionMoveY
                } else {
                    val pointerIndex = event.findPointerIndex(currentPointerId)
                    val pointerMoveX = event.getX(pointerIndex).toInt()
                    val pointerMoveY = event.getY(pointerIndex).toInt()
                    Log.d(TAG, "pointerDownX:${pointerDownX},pointerMoveX:${pointerMoveX}")
                    val diffValueX = pointerMoveX - pointerDownX
                    val diffValueY = pointerMoveY - pointerDownY
                    if (abs(diffValueX) > abs(diffValueY)) {
                        handleMoveEvent(diffValueX)
                        requestLayout()
                    }
                    pointerDownX = pointerMoveX
                    pointerDownY = pointerMoveY
                }
            }
            MotionEvent.ACTION_POINTER_UP -> {
                Log.d(TAG, "onTouchEvent---ACTION_POINTER_UP")
                val pointerIndex = event.findPointerIndex(currentPointerId)
                pointerDownX = event.getX(pointerIndex).toInt()
                pointerDownY = event.getY(pointerIndex).toInt()
                currentPointerId--
                currentPointerId = Math.max(currentPointerId, 0)
            }
            MotionEvent.ACTION_UP -> {
                Log.d(TAG, "onTouchEvent---ACTION_UP")
                val upFlagX = event.x.toInt()
                val upFlagY = event.y.toInt()
                var diffValueX = upFlagX - downFlagX
                var diffValueY = upFlagY - downFlagY
                if (diffValueX == 0 && usedMultiPointTouch) {
                    diffValueX = pointerDownX - pointerDownFlagX
                    diffValueY = pointerDownY - pointerDownFlagY
                }
                Log.d(TAG, "diffValueX:${diffValueX},diffValueY:${diffValueY},usedMultiPointTouch:${usedMultiPointTouch}")
                handleUpEvent(diffValueX)
                currentPointerId = 0
                usedMultiPointTouch = false
            }
        }
        return true
    }

    override fun dispatchDraw(canvas: Canvas?) {
        super.dispatchDraw(canvas)
        for (i in 0.until(pageChildCount)) {
            val left: Float
            val right: Float
            if (x0ValueMap[i] == null) {
                left = measuredWidth / 3.0f / pageChildCount * i + circlesDistance
                right = measuredWidth / 3.0f / pageChildCount * (i + 1) - circlesDistance
                val pair = Pair(left, right)
                x0ValueMap[i] = pair
            } else {
                left = x0ValueMap[i]!!.first
                right = x0ValueMap[i]!!.second
            }

            canvas?.drawCircle(
                measuredWidth / 3.0f + left,
                measuredHeight * 9 / 10 * 1.0f,
                (right - left) / 2,
                unSelectedPaint
            )
        }

        for (i in 0.until(pageChildCount)) {
            val condition = currentIndex == i
            if (condition) {
                val left: Float
                val right: Float
                if (x1ValueMap[i] == null) {
                    left = measuredWidth / 3.0f / pageChildCount * i + circlesDistance
                    right = measuredWidth / 3.0f / pageChildCount * (i + 1) - circlesDistance
                    val pair = Pair(left, right)
                    x1ValueMap[i] = pair
                } else {
                    left = x1ValueMap[i]!!.first
                    right = x1ValueMap[i]!!.second
                }

                canvas?.drawCircle(
                    measuredWidth / 3.0f + circleMovedX + circlesDistance,
                    measuredHeight * 9 / 10 * 1.0f,
                    (right - left) / 2,
                    selectedPaint
                )
            }
        }
    }

    override fun onFinishInflate() {
        super.onFinishInflate()
        addView(
            FirstLayout(context),
            ConstraintLayout.LayoutParams(
                ConstraintLayout.LayoutParams.MATCH_PARENT,
                ConstraintLayout.LayoutParams.MATCH_PARENT
            )
        )

        addView(
            SecondLayout(context),
            ConstraintLayout.LayoutParams(
                ConstraintLayout.LayoutParams.MATCH_PARENT,
                ConstraintLayout.LayoutParams.MATCH_PARENT
            )
        )

        addView(
            ThirdLayout(context),
            ConstraintLayout.LayoutParams(
                ConstraintLayout.LayoutParams.MATCH_PARENT,
                ConstraintLayout.LayoutParams.MATCH_PARENT
            )
        )

        addView(
            FourthLayout(context),
            ConstraintLayout.LayoutParams(
                ConstraintLayout.LayoutParams.MATCH_PARENT,
                ConstraintLayout.LayoutParams.MATCH_PARENT
            )
        )

        addView(
            FivethLayout(context),
            ConstraintLayout.LayoutParams(
                ConstraintLayout.LayoutParams.MATCH_PARENT,
                ConstraintLayout.LayoutParams.MATCH_PARENT
            )
        )
    }

    override fun performClick(): Boolean {
        return super.performClick()
    }

    private fun handleMoveEvent(diffValue: Int) {
        movedX += diffValue
        movedX = if (diffValue > 0) {
            circleMovedX -= diffValue / 3
            circleMovedX =
                Math.max(Math.max(currentIndex - 1, 0) * circleBaseMovedX, circleMovedX)
            Math.min(0, movedX)
        } else {
            circleMovedX -= diffValue / 2
            circleMovedX = Math.min(
                (Math.min(currentIndex + 1, pageChildCount - 1)) * circleBaseMovedX,
                circleMovedX
            )
            Math.max(-(pageChildCount - 1) * measuredWidth, movedX)
        }
    }

    private fun handleUpEvent(diffValue: Int) {
        currentMoveState = if (diffValue > 0) {
            STATE_RIGHT
        } else {
            STATE_LEFT
        }
        movedX = correctMovedX(movedX, measuredWidth)
        currentIndex = Math.abs(movedX) / measuredWidth
        circleMovedX = currentIndex * circleBaseMovedX
        requestLayout()
        currentMoveState = STATE_NONE
    }

    /*
    * 滑动值纠偏  确保整数倍
    * */
    private fun correctMovedX(movedX: Int, standardX: Int): Int {
        val remainedValue = movedX % standardX
        return when (movedX % standardX) {
            0 -> {
                movedX
            }
            else -> {
                val times = movedX / standardX
                if (Math.abs(remainedValue) >= circleBaseDistance * 3 / 5) {
                    if (STATE_RIGHT == currentMoveState) {
                        times * standardX
                    } else {
                        (times - 1) * standardX
                    }
                } else {
                    times * standardX
                }
            }
        }
    }

    fun initCurrentPage(page: Int) {
        updatePage = true
        currentPage = Math.min(Math.max(0, page), pageChildCount - 1)
    }

    fun showNextPage(page: Int, requestLayout: Boolean = true) {
        initCurrentPage(page)
        movedX = -currentPage * measuredWidth
        currentIndex = Math.abs(movedX) / measuredWidth
        circleMovedX = currentIndex * circleBaseMovedX
        if (requestLayout) {
            requestLayout()
        }
    }

    fun showNextPage(page: Int, view: View) {
        showNextPage(page)
        (get(currentPage) as ConstraintLayout).addView(view)
    }

    companion object {
        const val TAG = "ViewContainer"

        const val STATE_LEFT = 0x00
        const val STATE_RIGHT = 0x01
        const val STATE_NONE = 0x02
    }

}